using UnityEngine;
using System.Collections.Generic;

public class LadderMaker : MonoBehaviour
{
	private const float Depth = -3f;
	private const float DockingDist = 5f;
	
	private readonly Rect Boundary = new Rect(-110, 90, 220, 180);
	private readonly Vector2 YRange = new Vector2(80, -80);
	
	private Ladder m_ladder = null;
	
	private bool m_isActivate = false;
	
	private LineRenderer m_renderer = null;
	private Color m_color = Color.cyan;
	private float m_width = 2f;
	
	private List<LadderColumn> m_listLadderColumn = null;
	
	private bool m_isInput = false;
	private Vector3 m_inputPosition = Vector3.zero;
	
	private RungPoint m_rungPointBegin;
	private RungPoint m_rungPointEnd;
	
	private struct RungPoint
	{
		public int index;
		public Vector3 point;
		
		public void Reset()
		{
			index = -1;
			point = Vector3.zero;
		}
	}
	
	public static LadderMaker CreateLadderMaker(Ladder target)
	{
		GameObject ladderMakerObject = new GameObject("LadderMaker");
		ladderMakerObject.AddComponent<LineRenderer>();
		LadderMaker ladderMaker = ladderMakerObject.AddComponent<LadderMaker>();
		ladderMaker.Init(target);
		return ladderMaker;
	}
	
	private void Init(Ladder target)
	{
		m_ladder = target;
		m_listLadderColumn = new List<LadderColumn>();
		ResetRungPoints();
		
		m_renderer = GetComponent<LineRenderer>();
		if (m_renderer)
		{
			m_renderer.material = Material.Instantiate(Resources.Load("Materials/Column_Material")) as Material;
			m_renderer.SetColors(m_color, m_color);
			m_renderer.SetWidth(m_width, m_width);
			m_renderer.SetVertexCount(0);
		}
		else
		{
			Debug.LogError("Not found LineRenderer component");
		}
		
		m_isActivate = false;
	}
	
	public void Enable(bool isActive)
	{
		m_isActivate = isActive;
		
		if (m_isActivate = false)
		{
			m_renderer.SetVertexCount(0);
			ResetRungPoints();
		}
	}
	
	public void CreateLadderColumns(int count)
	{
		m_listLadderColumn.Clear();
		
		int xGap = (int)(Boundary.width / (count - 1));
		
		for (int i = 0; i < count; ++i)
		{
			int posX = i * xGap + (int)Boundary.x;
			LadderColumn ladderColumn = LadderColumn.Create(posX, (int)Boundary.y, (int)(Boundary.y - Boundary.height));
			m_ladder.AddLadderColumn(ladderColumn);
			m_listLadderColumn.Add(ladderColumn);
		}
		
		ResetRungPoints();
	}
	
	private void ResetRungPoints()
	{
		m_rungPointBegin.Reset();
		m_rungPointEnd.Reset();
	}
	
	private void Update () 
	{
		m_isInput = false;
		
		if (Input.touchCount > 0)
		{
			Touch touch = Input.GetTouch(0);
			m_inputPosition = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, Camera.main.nearClipPlane));
			m_isInput = true;
		}
		else if (Input.GetMouseButton(0))
		{
			m_inputPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
			m_isInput = true;
		}
		
		if (m_isInput)
		{
			Vector3 dockingPoint = Vector3.zero;
			int idxColumn = GetDockingPointOfLadderColumn(m_inputPosition, ref dockingPoint);
			if (idxColumn >= 0)
			{
				if (m_rungPointBegin.index < 0 || idxColumn == m_rungPointBegin.index)
				{
					m_rungPointBegin.index = idxColumn;
					m_rungPointBegin.point = dockingPoint;
				}
				else if (m_rungPointEnd.index < 0 || idxColumn == m_rungPointEnd.index)
				{
					if (Mathf.Abs(m_rungPointBegin.index - idxColumn) == 1)
					{
						m_rungPointEnd.index = idxColumn;
						m_rungPointEnd.point = dockingPoint;
					}
				}
			}
		}
		else
		{
			if (m_rungPointBegin.index >= 0 && m_rungPointEnd.index >= 0)
			{
				Vector2 rungBegin = Vector2.zero;
				Vector2 rungEnd = Vector2.zero;
				rungBegin.x = m_rungPointBegin.point.x;
				rungBegin.y = m_rungPointBegin.point.y;
				rungEnd.x = m_rungPointEnd.point.x;
				rungEnd.y = m_rungPointEnd.point.y;
				LadderRung ladderRung = LadderRung.Create(rungBegin, rungEnd);
				m_ladder.AddLadderRung(ladderRung);
			}
			
			ResetRungPoints();
		}
		
		UpdateLineRenderer();
	}
	
	private void UpdateLineRenderer()
	{
		if (m_renderer == null)
		{
			return;
		}
		
		m_renderer.SetVertexCount(0);
		
		if (m_rungPointBegin.index >= 0)
		{
			if (m_rungPointEnd.index >= 0)
			{
				m_renderer.SetVertexCount(2);
				m_renderer.SetPosition(0, m_rungPointBegin.point);
				m_renderer.SetPosition(1, m_rungPointEnd.point);
			}
			else if (m_isInput)
			{
				Vector3 inputPos = m_inputPosition;
				inputPos.z = LadderMaker.Depth;
				
				m_renderer.SetVertexCount(2);
				m_renderer.SetPosition(0, m_rungPointBegin.point);
				m_renderer.SetPosition(1, inputPos);
			}
		}
	}
	
	private int GetDockingPointOfLadderColumn(Vector3 point, ref Vector3 dockingPoint)
	{
		point.z = LadderColumn.Depth;
		
		int findIndex = -1;
		Vector3 findPoint = Vector3.zero;
		float minDist = float.MaxValue;
		int count = m_listLadderColumn.Count;
		
		for (int i = 0; i < count; ++i)
		{
			Vector3 closestPoint = m_listLadderColumn[i].GetClosestPoint(point);
			
			float dist = Vector3.Distance(closestPoint, point);
			if (dist >= minDist)
			{
				break;
			}
			
			minDist = dist;
			findIndex = i;
			findPoint = closestPoint;	
		}

		/*
		if (findIndex >= 0)
		{
			Debug.Log("Closest Point : Column[ " + findIndex + " ] " + findPoint + ", Dist : " + minDist);
		} */
		
		if (findIndex >= 0 && minDist <= DockingDist)
		{
			if (findPoint.y <= YRange.x && findPoint.y >= YRange.y)
			{
				if (m_listLadderColumn[findIndex].IsExistRung((int)findPoint.y) == false)
				{
					dockingPoint = findPoint;
					dockingPoint.z = LadderMaker.Depth;
					return findIndex;
				}
			}
		}
		
		return -1;
	}
}
